package cn.com.twoke.game.client.games.framework.core;

import cn.com.twoke.game.client.cache.ClientCacheManager;
import cn.com.twoke.game.client.games.framework.component.Component;
import cn.com.twoke.game.client.games.framework.component.LogicComponent;
import cn.com.twoke.game.client.games.framework.component.RenderComponent;
import cn.com.twoke.game.client.games.framework.system.RenderSystem;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.util.function.Function;

/**
 * 游戏启动
 */
public abstract class Game implements
        LogicComponent,
        RenderComponent, Runnable  {
	   /**
     * FPS
     */
    public static final int FPS_SET = 120;
    /**
     * UPS
     */
    public static final int UPS_SET = 120;

    protected boolean isRoomMaster = false;
    protected boolean isSinglePlayer = true;
    protected boolean network = false;
    protected String playerName = "自己";
    protected String roomId;

    protected final GamePanel panel;
    protected final GameWindow window;
    private Thread drawThread;
    private RenderSystem renderSystem;

    public boolean isNetwork() {
        return network;
    }

    public void setNetwork(boolean network) {
        this.network = network;
    }

    public void setPlayerName(String playerName) {
        this.playerName = playerName;
    }

    public String getPlayerName() {
        return playerName;
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    protected abstract String getTitle();

    public JFrame getWindow() {
        return window.getWindow();
    }

    public Game(Function<Game, GamePanel> panelGetter) {
        this.renderSystem = new RenderSystem();
    	this.panel = panelGetter.apply(this);
        this.window = new GameWindow((frame) -> {
            withComponent(frame);
            //		设置窗口聚焦监听处理
            frame.addWindowFocusListener(new WindowFocusListener() {
                @Override
                public void windowGainedFocus(WindowEvent e) {

                }

                @Override
                public void windowLostFocus(WindowEvent e) {
                    doWindowLostFocus(e);
                }
            });
        }, this, getTitle());
        initialzer();
        this.panel.requestFocus();
        startDrawGameLoop();
    }

    /**
     * 添加组件
     * @param frame
     */
    protected void withComponent(JFrame frame) {
        frame.add(panel);
    }
    protected void doWindowLostFocus(WindowEvent e) {
        panel.getGame().windowLostFocus();
    }

    public boolean isRoomMaster() {
        return isRoomMaster;
    }

    public void setRoomMaster(boolean roomMaster) {
        isRoomMaster = roomMaster;
    }

    @Override
    public void show() {
        window.open();
    }

    @Override
    public void hide() {
        window.close();
    }

    public void add(Component component) {
        if (null == component) return;

        if (component instanceof RenderComponent) {
            renderSystem.add((RenderComponent) component);
        }
    }


    @Override
    public void render(Graphics2D g) {
        renderSystem.render(g);
    }

    protected void startDrawGameLoop() {
		drawThread = new Thread(this);
        drawThread.start();
	}

	@Override
	public void run() {
		double timePerFrame = 1_000_000_000.0 / FPS_SET;
        double timePerUpdate = 1_000_000_000.0 / UPS_SET;
        long lastCheck = System.currentTimeMillis();;
        long previousTime = System.nanoTime();
        int frames = 0;
        int updates = 0;

        double deltaU = 0;
        double deltaF = 0;
        while (true) { // loop
            long currentTime = System.nanoTime();

            deltaU += (currentTime - previousTime) / timePerUpdate;
            deltaF += (currentTime - previousTime) / timePerFrame;
            previousTime = currentTime;

            if (deltaU >= 1) {
            	panel.requestFocus();
                this.update(deltaU);
                updates++;
                deltaU--;
            }

            if (deltaF >= 1) {
                panel.repaint();
                frames++;
                deltaF--;
            }

            if (System.currentTimeMillis() - lastCheck >= 1000 ) {
                lastCheck = System.currentTimeMillis();
//                System.out.println("FPS: " + frames + " | UPS: " + updates);
                frames = 0;
                updates = 0;
            }
        }
	}
	

	public void windowLostFocus() {}


	protected void initialzer() {}


    protected String withUserName(String title) {
        return ClientCacheManager.INSTANCE.getUsername()  == null ? title :
                "用户【" + ClientCacheManager.INSTANCE.getUsername() +  "】- " + title;
    }


    public void initGameState() {

    }

    public abstract String getId();
}
